package org.example;

import javax.sql.rowset.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.nio.file.*;
import java.sql.*;
import java.util.*;

public class ViewDBFrame extends JFrame {
    private JButton previousButton, nextButton, deleteButton, saveButton;
    private DataPanel dataPanel;
    private Component scrollPane;
    private final JComboBox<String> tableNames;
    private Properties properties;
    private CachedRowSet cachedRowSet;
    private Connection connection;

    public ViewDBFrame() throws SQLException, IOException {
        tableNames = new JComboBox<>();
        try {
            readDatabaseProperties();
            connection = getConnection();
            System.out.println();
            System.out.println("******************************");
            System.out.println("Connection established");
            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet metaDataResultSet = metaData.getTables(null, null, null, new String[] { "TABLE" });
            System.out.println("Tables obtained");
            while (metaDataResultSet.next()) {
                String table=metaDataResultSet.getString("TABLE_NAME");
                System.out.printf("got table:%s",table);
                System.out.println();
                tableNames.addItem(table);
            }
            tableNames.addActionListener(event -> showTable((String) tableNames.getSelectedItem()));
            add(tableNames, BorderLayout.NORTH);
            addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    try {
                        if (connection == null)
                            return;
                        System.out.println("Closing Connection...");
                        System.out.println("***************************");
                        connection.close();


                    } catch (SQLException sqlException) {
                        for (Throwable t : sqlException)
                            System.out.println(t);
                    }
                }
            });
            JPanel buttonPanel = new JPanel();
            add(buttonPanel, BorderLayout.SOUTH);

            previousButton = new JButton("Previous");
            previousButton.addActionListener(event -> showPreviousRow());
            buttonPanel.add(previousButton);

            nextButton = new JButton("Next");
            nextButton.addActionListener(event -> showNextRow());
            buttonPanel.add(nextButton);

            deleteButton = new JButton("Delete");
            deleteButton.addActionListener(event -> deleteRow());
            buttonPanel.add(deleteButton);

            saveButton = new JButton("Save");
            saveButton.addActionListener(event -> saveChanges());
            buttonPanel.add(saveButton);

            if (tableNames.getItemCount() > 0)
                showTable(tableNames.getItemAt(0));
//            display();
        } catch (SQLException sqlException) {
            for (Throwable t : sqlException)
                t.printStackTrace();
        }
    }

    // private void display(){
    // previousButton.setVisible(true);
    // nextButton.setVisible(true);
    // deleteButton.setVisible(true);
    // saveButton.setVisible(true);
    // }

    /**
     * Show the table with the given name
     * 
     * @param tableName the name of the table to display
     */
    public void showTable(String tableName) {
        try (PreparedStatement statement = connection.prepareStatement(
                String.format(
                        "SELECT * FROM %s", tableName));
                ResultSet resultSet = statement.executeQuery()) {
            RowSetFactory factory = RowSetProvider.newFactory();
            cachedRowSet = factory.createCachedRowSet();
            cachedRowSet.setTableName(tableName);
            cachedRowSet.populate(resultSet);
            if (scrollPane != null)
                remove(scrollPane);
            dataPanel = new DataPanel(cachedRowSet);
            scrollPane = new JScrollPane(dataPanel);
            add(scrollPane, BorderLayout.CENTER);
            validate();
            tableNames.setSelectedItem(tableName);
        } catch (SQLException sqlException) {
            for (Throwable t : sqlException)
                t.printStackTrace();
        }
    }

    public void showPreviousRow() {
        try {
            if (cachedRowSet == null || cachedRowSet.isFirst())
                return;
            cachedRowSet.previous();
            dataPanel.showRow(cachedRowSet);
        } catch (SQLException sqlException) {
            for (Throwable t : sqlException)
                t.printStackTrace();
        }
    }

    public void showNextRow() {
        try {
            if (cachedRowSet == null || cachedRowSet.isLast())
                return;
            cachedRowSet.next();
            dataPanel.showRow(cachedRowSet);
        } catch (SQLException sqlException) {
            for (Throwable t : sqlException)
                t.printStackTrace();
        }
    }

    public void deleteRow() {
        if (cachedRowSet == null)
            return;
        new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() throws Exception {
                cachedRowSet.deleteRow();
                cachedRowSet.acceptChanges(connection);
                if (cachedRowSet.isAfterLast())
                    if (!cachedRowSet.last())
                        cachedRowSet = null;
                return null;
            }

            @Override
            protected void done() {
                dataPanel.showRow(cachedRowSet);
            }
        }.execute();
    }

    public void saveChanges() {
        if (cachedRowSet == null)
            return;
        new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() throws Exception {
                dataPanel.setRow(cachedRowSet);
                cachedRowSet.acceptChanges(connection);
                return null;
            }
        }.execute();
    }

    private void readDatabaseProperties() throws IOException {
        String fileName = "database.properties";
        properties = new Properties();
        try (InputStream in = Files.newInputStream(Paths.get(fileName))) {
            properties.load(in);
            System.out.println("Properties loaded");
            System.out.println("******************************");
            System.out.printf("%s:%s", "jdbc.url", properties.getProperty("jdbc.url"));
            System.out.println();
            System.out.printf("%s:%s", "jdbc.username", properties.getProperty("jdbc.username"));
            System.out.println();
            System.out.printf("%s:%s", "jdbc.password", properties.getProperty("jdbc.password"));
            System.out.println();
        } catch (IOException ioException) {
            properties.setProperty("jdbc.url", "jdbc:mysql://localhost:3306/");
            properties.setProperty("jdbc.username", "root");
            properties.setProperty("jdbc.password", "A7btngqx");
            try(PrintStream stream=new PrintStream(fileName)){
                properties.store(stream, "init");
            }
        }
        String drivers = properties.getProperty("jdbc.drivers");
        if (drivers != null)
            System.setProperty("jdbc.drivers", drivers);
    }

    private Connection getConnection() throws SQLException {
        if (properties == null)
            return null;
        String url = properties.getProperty("jdbc.url");
        String username = properties.getProperty("jdbc.username");
        String password = properties.getProperty("jdbc.password");
        System.out.println("******************************");
        System.out.printf("...connecting to %s..", url);
        return DriverManager.getConnection(url, username, password);
    }


}
